package com.knowledgegraph.service;

import com.knowledgegraph.entity.Node;
import com.knowledgegraph.entity.NodeRelation;
import com.knowledgegraph.repository.NodeRelationRepository;
import com.knowledgegraph.repository.NodeRepository;
import org.apache.tinkerpop.gremlin.process.traversal.Path;
import org.apache.tinkerpop.gremlin.process.traversal.Scope;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class GraphService {

    @Autowired
    private NodeRepository nodeRepository;

    @Autowired
    private NodeRelationRepository nodeRelationRepository;

    public Graph buildTinkerGraph() {
        Graph graph = TinkerGraph.open();
        GraphTraversalSource g = graph.traversal();

        List<Node> nodes = nodeRepository.findAll();
        Map<Long, Vertex> nodeVertexMap = new HashMap<>();

        for (Node node : nodes) {
            Vertex vertex = graph.addVertex(
                    "id", node.getId(),
                    "name", node.getName(),
                    "nodeType", node.getNodeType(),
                    "description", node.getDescription(),
                    "properties", node.getProperties(),
                    "xPosition", node.getXPosition(),
                    "yPosition", node.getYPosition(),
                    "styleConfig", node.getStyleConfig()
            );
            nodeVertexMap.put(node.getId(), vertex);
        }

        List<NodeRelation> relations = nodeRelationRepository.findAll();
        for (NodeRelation relation : relations) {
            Vertex sourceVertex = nodeVertexMap.get(relation.getSourceNode().getId());
            Vertex targetVertex = nodeVertexMap.get(relation.getTargetNode().getId());

            if (sourceVertex != null && targetVertex != null) {
                Edge edge = sourceVertex.addEdge(
                        relation.getRelationType(),
                        targetVertex,
                        "relationId", relation.getId(),
                        "weight", relation.getWeight(),
                        "description", relation.getDescription(),
                        "properties", relation.getProperties(),
                        "isDirected", relation.getIsDirected()
                );
            }
        }

        return graph;
    }

    public List<Map<String, Object>> findShortestPath(Long sourceNodeId, Long targetNodeId) {
        Graph graph = buildTinkerGraph();
        GraphTraversalSource g = graph.traversal();

//        List<Map<String, Object>> pathResult = g.V()
//                .has("id", sourceNodeId)
//                .repeat(__.out().simplePath())
//                .until(__.has("id", targetNodeId))
//                .limit(1)
//                .path()
//                .by(__.valueMap(true))
//                .unfold()
//                .toList();
        // 获取Path对象
        List<Path> paths = g.V()
                .has("id", sourceNodeId)
                .repeat(__.out().simplePath())
                .until(__.has("id", targetNodeId))
                .limit(1)
                .path()
                .by(__.valueMap(true))
                .toList();

        // 转换Path为Map列表
        List<Map<Object, Object>> pathResult = new ArrayList<>();

        if (!paths.isEmpty()) {
            Path path = paths.get(0);
            for (Object step : path) {
                if (step instanceof Map) {
                    pathResult.add((Map<Object, Object>) step);
                }
            }
        }
        return resetObjectToString(pathResult);
    }

    public List<Map<String, Object>> findNeighbors(Long nodeId, int depth) {
        Graph graph = buildTinkerGraph();
        GraphTraversalSource g = graph.traversal();
        List<Map<Object, Object>> neighbors =  g.V()
                .has("id", nodeId)
                .repeat(__.both().simplePath())
                .times(depth)
                .dedup()
                .valueMap(true)
                .toList();

        return resetObjectToString(neighbors);
    }

    private List<Map<String, Object>> resetObjectToString(List<Map<Object, Object>> neighbors) {
        List<Map<String, Object>> fixed = new ArrayList<>();

        for (Map<Object, Object> row : neighbors) {
            Map<String, Object> newRow = new LinkedHashMap<>();
            row.forEach((k, v) -> newRow.put(String.valueOf(k), v));
            fixed.add(newRow);
        }
        return fixed;
    }

    public List<Map<String, Object>> findNodesByType(String nodeType) {
        Graph graph = buildTinkerGraph();
        GraphTraversalSource g = graph.traversal();

        List<Map<String, Object>> nodes = (List<Map<String, Object>>) (List<?>) g.V()
                .has("nodeType", nodeType)
                .valueMap(true)
                .toList();

        return nodes;
    }

    public Map<String, Long> getGraphStatistics() {
        Graph graph = buildTinkerGraph();
        GraphTraversalSource g = graph.traversal();

        Map<String, Long> stats = new HashMap<>();
        stats.put("nodeCount", g.V().count().next());
        stats.put("edgeCount", g.E().count().next());

        return stats;
    }

    public List<Map<String, Object>> findConnectedComponents() {
        Graph graph = buildTinkerGraph();
        GraphTraversalSource g = graph.traversal();
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> components = (List<Map<String, Object>>) (List<?>) g.V()
                .emit()
                .repeat(__.both().simplePath())
                .until(__.not(__.both().simplePath()))
                .group()
                .by(__.path().count(Scope.local))  // 修复：使用 Scope.local
                .unfold()
                .toList();

        return components;
    }

    public Double calculateNodeCentrality(Long nodeId) {
        Graph graph = buildTinkerGraph();
        GraphTraversalSource g = graph.traversal();

        Long degree = g.V()
                .has("id", nodeId)
                .bothE()
                .count()
                .next();

        Long totalNodes = g.V().count().next();

        return degree.doubleValue() / (totalNodes - 1);
    }

    public List<Map<String, Object>> findCycles(int maxDepth) {
        Graph graph = buildTinkerGraph();
        GraphTraversalSource g = graph.traversal();
        try {
            List<Path> paths = g.V()
                    .repeat(__.out().simplePath())
                    .times(maxDepth)
                    .cyclicPath()
                    .path()
                    .by(__.valueMap(true))
                    .toList();
            // 转换Path为Map
            List<Map<String, Object>> cycles = paths.stream()
                    .map(this::pathToMap)
                    .collect(Collectors.toList());
            return cycles;
        } catch (Exception e) {
            return new ArrayList<>();
        } finally {
            try {
                graph.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 将Path转换为Map的辅助方法
    private Map<String, Object> pathToMap(Path path) {
        Map<String, Object> cycleMap = new HashMap<>();

        List<Map<String, Object>> vertices = new ArrayList<>();
        List<String> vertexIds = new ArrayList<>();

        for (Object object : path) {
            if (object instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<Object, Object> vertexData = (Map<Object, Object>) object;
                Map<String, Object> convertedVertex = convertMapKeys(vertexData);
                vertices.add(convertedVertex);

                // 提取顶点ID
                Object id = convertedVertex.get("id");
                if (id != null) {
                    vertexIds.add(id.toString());
                }
            }
        }

        cycleMap.put("length", vertices.size());
        cycleMap.put("vertices", vertices);
        cycleMap.put("vertexIds", vertexIds);
        cycleMap.put("path", path.toString());

        return cycleMap;
    }
    // 转换Map键类型的辅助方法
    private Map<String, Object> convertMapKeys(Map<Object, Object> originalMap) {
        Map<String, Object> convertedMap = new HashMap<>();
        for (Map.Entry<Object, Object> entry : originalMap.entrySet()) {
            String key = entry.getKey().toString();
            Object value = entry.getValue();

            // 处理属性值可能是列表的情况
            if (value instanceof List) {
                List<?> listValue = (List<?>) value;
                if (listValue.size() == 1) {
                    convertedMap.put(key, listValue.get(0));
                } else {
                    convertedMap.put(key, value);
                }
            } else {
                convertedMap.put(key, value);
            }
        }
        return convertedMap;
    }
}